#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/evp.h>
#include <openssl/rand.h>
#include <openssl/err.h>
void piszemy_hex(char * napis,unsigned char buf[], int k);

/* Sprawdzenie:
$ echo -n "0123456789abcdef" | openssl enc -aes-128-cfb -nosalt 
-K "01010101010101010101010101010101" -iv "02020202020202020202020202020202" | 
hexdump -C | awk '{print $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17}'

lub jeśli mamy jedno hasło w tym wypadku "a"
$echo -n "0123456789abcdef" | openssl enc -aes-128-cfb -nosalt -pass pass:a -P 
key=0CC175B9C0F1B6A831C399E269772661
iv =CEC520EA51EA0A47E87295FA3245A605

$echo -n "0123456789abcdef" | openssl enc -aes-128-cfb -nosalt -pass pass:a | 
hexdump -C | awk '{print $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17}'
32db6fc4afc94f2b1068b4f4e9c7b61f

Key = MD5(password + salt) IV = MD5(Key + password + salt)
*/

#define RODZAJ_KODOWANIA EVP_aes_128_cfb()
#define MAX_DANE 100

int main (int argc, char *argv[])
{
  EVP_CIPHER_CTX ctx;
  char key[EVP_MAX_KEY_LENGTH]; /*Jak rozumiem key to hasło*/
  char iv[EVP_MAX_IV_LENGTH];   /*takie dodatkowe zabezpieczenie losowa wartość, którą można zamieścić jawnie */
  char haslo[MAX_DANE] = "a";
  char str[MAX_DANE] = "0123456789abcdef";
  int  istr=0;
  char wynik[MAX_DANE];
  int  iwynik=0;

  const EVP_MD *dgst=EVP_md5();
  // Generujemy key z hasła przy aes_128 mamy md5
  EVP_BytesToKey(RODZAJ_KODOWANIA, dgst, NULL, haslo, strlen((char*)haslo), 1, key, iv);

  //szyfrujemy 
  OPENSSL_add_all_algorithms_conf();

  EVP_CIPHER_CTX_init(&ctx);
  if(!EVP_EncryptInit_ex(&ctx, RODZAJ_KODOWANIA, NULL, key, iv))
        printf("\n Błąd inicjowania kodowania!! \n");
  istr=strlen(str);
  piszemy_hex("dane     =\t",(char *)str,istr);

  EVP_EncryptUpdate (&ctx, wynik,&iwynik,str,istr);
  EVP_EncryptFinal (&ctx, str,&istr);
  EVP_CIPHER_CTX_cleanup(&ctx);

  piszemy_hex("zakodowano\t",(char *)wynik,iwynik);
  piszemy_hex("key       \t",(char *)key,16);
  piszemy_hex("iv        \t",(char *)iv,16);

//Sprawdzamy czy działa. Zerujemy co się da.
  istr=MAX_DANE; memset(str,0,istr);
  piszemy_hex("zero      \t",(char*)str,16);

//dekodowanie
  EVP_CIPHER_CTX_init(&ctx);
  if(!EVP_DecryptInit_ex(&ctx, RODZAJ_KODOWANIA, NULL, key, iv))
        printf("\n Błąd inicjowania kodowania!! \n");  
  EVP_DecryptUpdate (&ctx,str,&istr,wynik,iwynik);
  piszemy_hex("odkodowano\t",(unsigned char *)str,istr);
  EVP_DecryptFinal (&ctx,str,&istr);
  EVP_CIPHER_CTX_cleanup(&ctx);

return 0;
}
